home *** CD-ROM | disk | FTP | other *** search
- /*
- File: WAVE.c
-
- Contains: Routines demonstrating how to parse Microsoft's WAVE sound files.
-
- Written by: Mark Cookson
-
- Copyright: Copyright ©1996-1999 by Apple Computer, Inc., All Rights Reserved.
-
- You may incorporate this Apple sample source code into your program(s) without
- restriction. This Apple sample source code has been provided "AS IS" and the
- responsibility for its operation is yours. You are not permitted to redistribute
- this Apple sample source code as "Apple sample source code" after having made
- changes. If you're going to re-distribute the source, we require that you make
- it clear in the source that the code was descended from Apple sample source
- code, but that you've made changes.
-
- Change History (most recent first):
- 8/31/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1
-
-
- */
- #include "WAVE.h"
-
- /* Please note that this code was written in less than 6 hours, does very little error checking
- and probably will not work for all files. I have tested it with the WAVE files at my
- disposal and it worked with them. Your milage may vary.
-
- I do know that it will probably be impossible to get the Mac's IMA decompressor to
- decompress IMA (and ADPCM) compressed WAVE files because the Mac's IMA has a different
- file format from the WAVE file and the decompressor cannot correctly decompress WAVE files.
-
- The Mac IMA compressed file has predictor bytes in the data stream that the WAVE files
- do not have.
- */
-
- /* Given an WAVE File gets the sample rate and other relavent pieces of information.
- This has been modified from its orignal form found in the Develop 11 MultiBuffer source. */
- /*-----------------------------------------------------------------------*/
- OSErr ASoundGetWAVEHeader (SoundInfoPtr theSoundInfo,
- long *dataStart,
- long *length)
- /*-----------------------------------------------------------------------*/
- {
- WAVETemplatePtr WAVETemplate; /* ...for ease of access */
- long filePosition = kInit,
- byteCount = kInit;
- short format = kInit;
- unsigned short chunkFlags = kInit; /* remember chunks we've seen */
- OSErr err = noErr;
- char chunkBuffer[kWAVEChunkBufferSize];
-
- *dataStart = kInit;
-
- /* Now for the fun part! We're going to assume that these are generic, non-compressed
- WAVE files and parse accordingly... */
-
- do {
- /* Position ourselves at the beginning of the next chunk and read in
- a hunk-o-data... */
- err = SetFPos (theSoundInfo->refNum, fsFromStart, filePosition);
- if (err != noErr) {
- DebugPrint ("\pSetFPos failed!");
- break;
- }
-
- byteCount = kWAVEChunkBufferSize;
- err = FSRead (theSoundInfo->refNum, &byteCount, chunkBuffer); /* read a chunk */
- if ((err != noErr) && (err != eofErr)) {
- DebugPrint ("\pFSRead failed!");
- break;
- }
-
- /* Now, position the template over the data... */
- WAVETemplate = (WAVETemplatePtr) chunkBuffer;
-
- /* assume a failure and break out of the do {} while loop if the next case isn't found.
- if the case is found and no other error is detected, then each case needs to set noErr */
- err = kBadWAVEFileFormat;
- switch (WAVETemplate->generic.ckID) {
- case WAVEFORMID:
- chunkFlags |= kWAVEFORMID; /* otherwise mark it found */
- filePosition += 12;
- err = noErr;
- break;
- case FormatID:
- chunkFlags |= kFormatID; /* otherwise mark it found */
- format = SwapShort (WAVETemplate->fmt.wFormatTag);
- theSoundInfo->needsMasking = false;
- switch (format) {
- case WAVE_FORMAT_PCM:
- err = SetupDBHeader (theSoundInfo,
- SwapLong (WAVETemplate->fmt.dwSamplesPerSec),
- ((SwapShort (WAVETemplate->fmt.wBlockAlign) / SwapShort (WAVETemplate->fmt.wChannels)) * 8),
- SwapShort (WAVETemplate->fmt.wChannels),
- notCompressed,
- NoneType);
- break;
- case WAVE_FORMAT_MULAW:
- case IBM_FORMAT_MULAW:
- err = SetupDBHeader (theSoundInfo,
- SwapLong (WAVETemplate->fmt.dwSamplesPerSec),
- ((SwapShort (WAVETemplate->fmt.wBlockAlign) / SwapShort (WAVETemplate->fmt.wChannels)) * 8),
- SwapShort (WAVETemplate->fmt.wChannels),
- fixedCompression,
- kULawCompression);
- filePosition += 2; /* This is here because the only µlaw compressed file I ever saw needed it. */
- break;
- default:
- DebugPrint ("\pCan't deal with this file format");
- err = kUnknownFormat;
- break;
- }
- filePosition += 24;
- break;
- case WAVEDataID:
- chunkFlags |= kWAVEDataID;
- *length = ReverseLong (WAVETemplate->waveData.ckSize);
- filePosition += 8;
- *dataStart = filePosition;
- err = noErr;
- break;
- /* We don't care about any of these, and my handling of them is probably not correct */
- case WAVEID:
- err = noErr;
- filePosition += 4;
- break;
- case WAVEListID:
- err = noErr;
- filePosition += 4;
- break;
- case SilenceID:
- err = noErr;
- filePosition += 4;
- break;
- case CueID:
- err = noErr;
- filePosition += 24;
- break;
- case FactID:
- err = noErr;
- filePosition += 4;
- break;
- case PlaylistID:
- err = noErr;
- filePosition += 12;
- break;
- case AssocDataID:
- err = noErr;
- filePosition += 32;
- break;
- case LabelID:
- err = noErr;
- filePosition += 4;
- break;
- case NoteID:
- err = noErr;
- filePosition += 4;
- break;
- case TextWithLenID:
- err = noErr;
- filePosition += 16;
- break;
- case EmbededFileID:
- err = noErr;
- filePosition += 8;
- break;
- default:
- //DebugPrint ("\pSaw a field we didn't know about, this doesn't have to be bad");
- /* Start walking through the file looking for an ID we know about.
- This could get ugly, but what the heck... */
- filePosition += 1;
- err = noErr;
- break;
- }
- } while (stillMoreDataWAVEToRead);
-
- if (err != noErr) {
- DebugPrint ("\pError in ASoundGetWAVEHeader");
- }
-
- return err;
- }
-
- /* These are here for the endian conversion required to parse the header.
- The endian conversion used when playing a WAVE file is much better, don't worry.
- */
- short SwapShort (const short theShort) {
- char tempChar = kInit;
- short newShort = kInit;
-
- tempChar = ((char *)&theShort)[0];
- ((char *)&newShort)[0] = ((char *)&theShort)[1];
- ((char *)&newShort)[1] = tempChar;
-
- return newShort;
- }
-
- long SwapLong (const long theLong) {
- short tempShort = kInit;
- long newLong = kInit;
-
- tempShort = SwapShort (((short *)&theLong)[0]);
- ((short *)&newLong)[0] = tempShort;
- tempShort = SwapShort (((short *)&theLong)[1]);
- ((short *)&newLong)[1] = tempShort;
-
- return newLong;
- }
-
- long ReverseLong (const long theLong) {
- char tempChar = kInit,
- i = kInit;
- long newLong = kInit;
-
- for (i = nil; i < 2; i++) {
- tempChar = ((char *)&theLong)[i];
- ((char *)&newLong)[i] = ((char *)&theLong)[3-i];
- ((char *)&newLong)[3-i] = tempChar;
- }
-
- return newLong;
- }